import Menu from 'ant-design-vue/es/menu';
import Icon from 'ant-design-vue/es/icon';
import Badge from 'ant-design-vue/es/badge';

export default {
  name: 'SMenu',
  props: {
    menu: {
      type: Array,
      required: true,
    },
    theme: {
      type: String,
      required: false,
      default: 'dark',
    },
    mode: {
      type: String,
      required: false,
      default: 'inline',
    },
    collapsed: {
      type: Boolean,
      required: false,
      default: false,
    },
  },
  data() {
    return {
      openKeys: [],
      selectedKeys: [],
      cachedOpenKeys: [],
    };
  },
  computed: {
    rootSubmenuKeys: vm => {
      const keys = [];
      vm.menu.forEach(item => keys.push(item.path));
      return keys;
    },
  },
  mounted() {
    this.updateMenu();
  },
  watch: {
    collapsed(val) {
      if (val) {
        this.cachedOpenKeys = this.openKeys.concat();
        this.openKeys = [];
      } else {
        this.openKeys = this.cachedOpenKeys;
      }
    },
    $route: function() {
      this.updateMenu();
    },
    menu() {
      this.updateMenu();
    },
  },
  methods: {
    // select menu item
    onOpenChange(openKeys) {
      // 在水平模式下时执行，并且不再执行后续
      if (this.mode === 'horizontal') {
        this.openKeys = openKeys;
        return;
      }
      // 非水平模式时
      const latestOpenKey = openKeys.find(key => !this.openKeys.includes(key));
      if (!this.rootSubmenuKeys.includes(latestOpenKey)) {
        this.openKeys = openKeys;
      } else {
        this.openKeys = latestOpenKey ? [latestOpenKey] : [];
      }
    },
    onSelect({ item, key, selectedKeys }) {
      this.selectedKeys = selectedKeys;
      this.$emit('select', { item, key, selectedKeys });
    },
    updateMenu() {
      const routes = this.$route.matched.concat();
      const { hidden } = this.$route.meta;
      if (routes.length >= 3 && hidden) {
        routes.pop();
        this.selectedKeys = [routes[routes.length - 1].path];
      } else {
        // this.selectedKeys = [routes.pop().path]
        this.selectedKeys = [this.getSelectedKey(routes.pop())];
      }
      const openKeys = [];
      if (this.mode === 'inline') {
        routes.forEach(item => {
          openKeys.push(item.path);
        });
      }

      this.collapsed ? (this.cachedOpenKeys = openKeys) : (this.openKeys = openKeys);
    },
    // 获取选中的菜单 key
    getSelectedKey(route) {
      if (route) {
        const { path, parent } = route;
        if (this.containPath(this.menu, path)) {
          return path;
        } else {
          return this.getSelectedKey(parent);
        }
      }
      return 'undefined';
    },
    // 判断当前菜单是否包含 path
    containPath(menuList, path) {
      for (let i = 0; i < menuList.length; i++) {
        const item = menuList[i];
        if (item.path === path) {
          return true;
        } else if (item.children && item.children.length > 0) {
          const childrenContain = this.containPath(item.children, path);
          if (childrenContain) {
            return true;
          }
        }
      }
      return false;
    },
    // render
    renderItem(menu) {
      if (!menu.hidden) {
        return menu.children && !menu.hideChildrenInMenu ? this.renderSubMenu(menu) : this.renderMenuItem(menu);
      }
      return null;
    },
    renderMenuItem(menu) {
      const target = menu.meta.target || null;
      const CustomTag = target ? 'a' : 'router-link';
      // const props = { to: { name: menu.name } }
      // 解决 混合导航跳转问题
      const props = { to: { path: menu.redirect || menu.path } };
      const style = 'width: 100%; display: flex; justify-content: space-between; align-items: center';
      const attrs = { href: menu.path, target: menu.meta.target, style };

      if (menu.children && menu.hideChildrenInMenu) {
        // 把有子菜单的 并且 父菜单是要隐藏子菜单的
        // 都给子菜单增加一个 hidden 属性
        // 用来给刷新页面时， selectedKeys 做控制用
        menu.children.forEach(item => {
          item.meta = Object.assign(item.meta, { hidden: true });
        });
      }
      const badgeNode = this.createBadge(menu);
      const menuContent = (
        <CustomTag {...{ props, attrs }}>
          <div>
            {this.renderIcon(menu.meta.icon)}
            <span>{menu.meta.title}</span>
          </div>
          {badgeNode}
        </CustomTag>
      );
      return (
        <Menu.Item {...{ key: menu.path }}>
          {menuContent}
        </Menu.Item>
      );
    },
    createBadge(menu) {
      const badge = menu.meta && menu.meta.badge;
      if (badge !== undefined) {
        const badgeProps = {};
        if (badge === 'dot') {
          badgeProps.dot = true;
          badgeProps.numberStyle = { transform: 'translateX(-50%)' };
        } else {
          badgeProps.count = badge;
          badgeProps.numberStyle = { padding: '0 6px', fontWeight: 200 };
        }
        return (
          <Badge {...{ props: badgeProps }} />
        );
      }
      return null;
    },
    renderSubMenu(menu) {
      const itemArr = [];
      if (!menu.hideChildrenInMenu) {
        menu.children.forEach(item => itemArr.push(this.renderItem(item)));
      }
      const badge = this.createBadge(menu);
      const menuContent = (
        <span slot="title" style="display: flex; justify-content: space-between; align-items: center;">
          <div>
            {this.renderIcon(menu.meta.icon)}
            <span>{menu.meta.title}</span>
          </div>
          {badge}
        </span>
      );
      return (
        <Menu.SubMenu {...{ key: menu.path }}>
          {menuContent}
          {itemArr}
        </Menu.SubMenu>
      );
    },
    renderIcon(icon) {
      if (icon === 'none' || icon === undefined) {
        return null;
      }
      const props = {};
      typeof (icon) === 'object' ? props.component = icon : props.type = icon;
      return (
        <Icon {... { props } }/>
      );
    },
  },

  render() {
    const dynamicProps = {
      props: {
        mode: this.mode,
        theme: this.theme,
        openKeys: this.openKeys,
        selectedKeys: this.selectedKeys,
      },
      on: {
        openChange: this.onOpenChange,
        select: this.onSelect,
      },
    };

    const menuTree = this.menu.map(item => {
      if (item.hidden) {
        return null;
      }
      return this.renderItem(item);
    });

    return (<Menu {...dynamicProps}>{menuTree}</Menu>);
  },
};
